package com.douqu.game.core.util;

import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 *
 * 2018-01-12
 */
public class LogUtils {

    private static LOG_LEVEL logLevel = LOG_LEVEL.DEBUG;

    public enum LOG_LEVEL
    {
        DEBUG(1),
        INFO(2),
        WARN(3),
        ERROR(4)
        ;

        int id;

        LOG_LEVEL(int id)
        {
            this.id = id;
        }

        public int getId()
        {
            return id;
        }

        public static LOG_LEVEL forNumber(int id)
        {
            for(LOG_LEVEL item : values())
            {
                if(item.getId() == id)
                    return item;
            }
            return null;
        }
    }

    public static void errorException(Exception e)
    {
        LogUtils.error(collectExceptionStackMsg(e));
    }

    /**
     * 收集异常堆栈信息
     * */
    private static String collectExceptionStackMsg(Exception e)
    {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, true);
        String result = "";
        try{
            e.printStackTrace(pw);
            result = sw.toString();
        }catch (Exception e1){
            e1.printStackTrace();
        }finally {
            try {
                pw.close();
                sw.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        return result;
    }

    public static void debug(Object... content) {
        if (logLevel.getId() <= LOG_LEVEL.DEBUG.getId()) {
            Logger logger = getLogger();
            if(logger != null)
            {
                logger.debug(getContent(content));
            }
        }
    }

    public static void debug(Object content) {
        if (logLevel.getId() <= LOG_LEVEL.DEBUG.getId()) {
            Logger logger = getLogger();
            if(logger != null)
            {
                logger.debug(getContent(content));
            }
        }
    }

    public static void info(Object... content) {

        if(logLevel.getId() <= LOG_LEVEL.INFO.getId()){
            Logger logger = getLogger();
            if(logger != null)
            {
                logger.info(getContent(content));
            }
        }
    }

    public static void info(Object content) {

        if(logLevel.getId() <= LOG_LEVEL.INFO.getId()){
            Logger logger = getLogger();
            if(logger != null)
            {
                logger.info(getContent(content));
            }
        }
    }


    public static void warn(Object... content) {
        if(logLevel.getId() <= LOG_LEVEL.WARN.getId()){
            Logger logger = getLogger();
            if(logger != null)
            {
                logger.warn(getContent(content));
            }
        }
    }

    public static void warn(Object content) {
        if(logLevel.getId() <= LOG_LEVEL.WARN.getId()){
            Logger logger = getLogger();
            if(logger != null)
            {
                logger.warn(getContent(content));
            }
        }
    }

    public static void error(Object... content) {
        if(logLevel.getId() <= LOG_LEVEL.ERROR.getId()){
            Logger logger = getLogger();
            if(logger != null)
            {
                logger.error(getContent(content));
            }
         }
    }

    public static void error(Object content) {
        if(logLevel.getId() <= LOG_LEVEL.ERROR.getId()){
            Logger logger = getLogger();
            if(logger != null)
            {
                logger.error(getContent(content));
            }
        }
    }


    private static Map<String, Logger> loggerMap = new ConcurrentHashMap<>();

    public static Logger getLogger()
    {
        StackTraceElement element = null;
        try {
            element = Thread.currentThread().getStackTrace()[3];
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

        Logger logger = loggerMap.get(element.getClassName());
        if(logger == null)
        {
            logger = Logger.getLogger(element.getClass());
            loggerMap.put(element.getClassName(), logger);
        }
        return logger;
    }

    private static String getContent(Object... contents)
    {
        StackTraceElement element = null;
        try {
            element = Thread.currentThread().getStackTrace()[3];
            String result = "";
            if(contents.length > 1)
            {
                if(contents[0].toString().indexOf("{0}") != -1)
                {
                    Object[] objs = Arrays.copyOfRange(contents, 1, contents.length);
                    String content = MessageFormat.format(contents[0].toString(), objs);
                    result = StringUtils.appendObject(element.getClassName(), ":", element.getLineNumber(),
                            " [", Thread.currentThread().getName(), "] [", element.getMethodName(), "] -> ", content);
                }
                else
                {
                    result = StringUtils.appendObject(element.getClassName(), ":", element.getLineNumber(),
                            " [", Thread.currentThread().getName(), "] [", element.getMethodName(), "] -> ", contents);
                }
            }
            else
            {
                result = StringUtils.appendObject(element.getClassName(), ":", element.getLineNumber(),
                        " [", Thread.currentThread().getName(), "] [", element.getMethodName(), "] -> ", contents);
            }
            return result;
//            String[] clsNames = element.getClassName().split("\\.");
//            return clsNames[clsNames.length-1] + ":" + element.getLineNumber() +  " [" + element.getMethodName() + "] -> " + content;
        } catch (Exception e) {
            return "";
        }
    }

    public static LOG_LEVEL getLogLevel() {
        return logLevel;
    }

    public static void setLogLevel(LOG_LEVEL logLevel) {
        LogUtils.logLevel = logLevel;
    }
}